package com.zzh.webhook.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.exec.*;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class CommandExecutor {

    /**
     * 执行命令并返回输出结果，同时实时打印输出
     *
     * @param command 要执行的命令
     * @param workDir 工作目录
     * @return 命令执行结果
     */
    public String execute(String command, String workDir) throws IOException {
        log.info("Executing command: {} in directory: {}", command, workDir);
        
        CommandLine cmdLine = CommandLine.parse(command);
        DefaultExecutor executor = new DefaultExecutor();
        
        if (workDir != null) {
            executor.setWorkingDirectory(new File(workDir));
        }
        
        // 创建一个输出流，同时捕获输出并实时打印
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
        TeeOutputStream teeOutputStream = new TeeOutputStream(System.out, outputStream);
        TeeOutputStream teeErrorStream = new TeeOutputStream(System.err, errorStream);
        PumpStreamHandler streamHandler = new PumpStreamHandler(teeOutputStream, teeErrorStream);
        executor.setStreamHandler(streamHandler);
        
        // 设置环境变量，确保命令能够找到
        Map<String, String> env = new HashMap<>(System.getenv());
        
        // 添加常见的Maven和Java路径到PATH环境变量
        String path = env.get("PATH");
        if (path != null) {
            // 添加常见的Maven路径
            String additionalPaths = "";
            if (System.getenv("MAVEN_HOME") != null) {
                additionalPaths += File.pathSeparator + System.getenv("MAVEN_HOME") + File.separator + "bin";
            }
            if (System.getenv("M2_HOME") != null) {
                additionalPaths += File.pathSeparator + System.getenv("M2_HOME") + File.separator + "bin";
            }
            
            // 添加常见的Java路径
            if (System.getenv("JAVA_HOME") != null) {
                additionalPaths += File.pathSeparator + System.getenv("JAVA_HOME") + File.separator + "bin";
            }
            
            // 更新PATH
            env.put("PATH", path + additionalPaths);
        }
        
        executor.setExitValues(new int[]{0, 1, 2});
        
        try {
            int exitValue = executor.execute(cmdLine, env);
            String output = outputStream.toString(StandardCharsets.UTF_8.name());
            String error = errorStream.toString(StandardCharsets.UTF_8.name());
            
            log.info("Command executed with exit code: {}", exitValue);
            if (exitValue != 0) {
                log.warn("Command output: {}", output);
                log.warn("Command error: {}", error);
            } else {
                log.debug("Command output: {}", output);
            }
            
            return output;
        } catch (IOException e) {
            log.error("Error executing command: {}", command, e);
            throw e;
        }
    }
    
    /**
     * 执行异步命令，不等待结果，但实时打印输出
     *
     * @param command 要执行的命令
     * @param workDir 工作目录
     */
    public void executeAsync(String command, String workDir) throws IOException {
        log.info("Executing async command: {} in directory: {}", command, workDir);
        
        CommandLine cmdLine = CommandLine.parse(command);
        DefaultExecutor executor = new DefaultExecutor();
        
        if (workDir != null) {
            executor.setWorkingDirectory(new File(workDir));
        }
        
        // 创建一个输出流，同时捕获输出并实时打印
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
        TeeOutputStream teeOutputStream = new TeeOutputStream(System.out, outputStream);
        TeeOutputStream teeErrorStream = new TeeOutputStream(System.err, errorStream);
        PumpStreamHandler streamHandler = new PumpStreamHandler(teeOutputStream, teeErrorStream);
        executor.setStreamHandler(streamHandler);
        
        // 设置环境变量，确保命令能够找到
        Map<String, String> env = new HashMap<>(System.getenv());
        
        // 添加常见的Maven和Java路径到PATH环境变量
        String path = env.get("PATH");
        if (path != null) {
            // 添加常见的Maven路径
            String additionalPaths = "";
            if (System.getenv("MAVEN_HOME") != null) {
                additionalPaths += File.pathSeparator + System.getenv("MAVEN_HOME") + File.separator + "bin";
            }
            if (System.getenv("M2_HOME") != null) {
                additionalPaths += File.pathSeparator + System.getenv("M2_HOME") + File.separator + "bin";
            }
            
            // 添加常见的Java路径
            if (System.getenv("JAVA_HOME") != null) {
                additionalPaths += File.pathSeparator + System.getenv("JAVA_HOME") + File.separator + "bin";
            }
            
            // 更新PATH
            env.put("PATH", path + additionalPaths);
        }
        
        executor.setExitValues(new int[]{0, 1, 2});
        
        ExecuteResultHandler handler = new ExecuteResultHandler() {
            @Override
            public void onProcessComplete(int exitValue) {
                log.info("Async command completed with exit code: {}", exitValue);
                String output = outputStream.toString();
                String error = errorStream.toString();
                if (exitValue != 0) {
                    log.warn("Async command output: {}", output);
                    log.warn("Async command error: {}", error);
                } else {
                    log.debug("Async command output: {}", output);
                }
            }

            @Override
            public void onProcessFailed(ExecuteException e) {
                log.error("Async command failed", e);
                String output = outputStream.toString();
                String error = errorStream.toString();
                log.error("Async command output: {}", output);
                log.error("Async command error: {}", error);
            }
        };
        
        executor.execute(cmdLine, env, handler);
    }
    
    /**
     * 一个简单的输出流，可以将输出同时写入两个流
     */
    private static class TeeOutputStream extends OutputStream {
        private final OutputStream out1;
        private final OutputStream out2;
        
        public TeeOutputStream(OutputStream out1, OutputStream out2) {
            this.out1 = out1;
            this.out2 = out2;
        }
        
        @Override
        public void write(int b) throws IOException {
            out1.write(b);
            out2.write(b);
        }
        
        @Override
        public void write(byte[] b) throws IOException {
            out1.write(b);
            out2.write(b);
        }
        
        @Override
        public void write(byte[] b, int off, int len) throws IOException {
            out1.write(b, off, len);
            out2.write(b, off, len);
        }
        
        @Override
        public void flush() throws IOException {
            out1.flush();
            out2.flush();
        }
        
        @Override
        public void close() throws IOException {
            try {
                out1.close();
            } finally {
                out2.close();
            }
        }
    }
} 